import schedule
import time
import threading
from datetime import datetime, timedelta
from typing import Dict, List, Callable, Optional, Any
from enum import Enum
import json
from pathlib import Path

from .data_fetcher import DataFetcher
from .data_storage import DataStorage
from .utils.config import get_settings
from .utils.logger import get_logger
from .utils.validators import DataValidator, ValidationError

logger = get_logger("ScheduleManager")


class TaskStatus(Enum):
    """任务状态枚举"""
    PENDING = "pending"
    RUNNING = "running"
    COMPLETED = "completed"
    FAILED = "failed"
    CANCELLED = "cancelled"


class ScheduledTask:
    """定时任务类"""

    def __init__(self, task_id: str, name: str, func: Callable,
                 symbol: str, interval: str, schedule_time: str = None):
        self.task_id = task_id
        self.name = name
        self.func = func
        self.symbol = symbol
        self.interval = interval
        self.schedule_time = schedule_time
        self.status = TaskStatus.PENDING
        self.last_run = None
        self.next_run = None
        self.error_message = None
        self.created_at = datetime.now()

    def update_status(self, status: TaskStatus, error_message: str = None):
        """更新任务状态"""
        self.status = status
        self.last_run = datetime.now()
        if error_message:
            self.error_message = error_message

    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            'task_id': self.task_id,
            'name': self.name,
            'symbol': self.symbol,
            'interval': self.interval,
            'schedule_time': self.schedule_time,
            'status': self.status.value,
            'last_run': self.last_run.isoformat() if self.last_run else None,
            'next_run': self.next_run.isoformat() if self.next_run else None,
            'error_message': self.error_message,
            'created_at': self.created_at.isoformat()
        }


class ScheduleManager:
    """定时任务管理器"""

    def __init__(self):
        self.settings = get_settings()
        self.logger = logger
        self.data_fetcher = DataFetcher()
        self.data_storage = DataStorage()
        self.tasks: Dict[str, ScheduledTask] = {}
        self.scheduler_thread = None
        self.is_running = False
        self.lock = threading.Lock()

    def start(self):
        """启动定时任务管理器"""
        if self.is_running:
            self.logger.warning("Schedule manager is already running")
            return

        self.is_running = True
        self.scheduler_thread = threading.Thread(target=self._run_scheduler, daemon=True)
        self.scheduler_thread.start()
        self.logger.info("Schedule manager started")

    def stop(self):
        """停止定时任务管理器"""
        if not self.is_running:
            return

        self.is_running = False
        schedule.clear()
        self.logger.info("Schedule manager stopped")

    def _run_scheduler(self):
        """运行调度器主循环"""
        while self.is_running:
            try:
                schedule.run_pending()
                time.sleep(1)
            except Exception as e:
                self.logger.error(f"Error in scheduler loop: {e}")
                time.sleep(5)

    def add_task(self, symbol: str, interval: str, schedule_time: str = None,
                 task_name: str = None) -> str:
        """添加定时任务"""
        try:
            # 验证输入
            if not DataValidator.validate_symbol(symbol):
                raise ValidationError(f"Invalid symbol: {symbol}")

            if not DataValidator.validate_interval(interval):
                raise ValidationError(f"Invalid interval: {interval}")

            if schedule_time and not DataValidator.validate_time_format(schedule_time):
                raise ValidationError(f"Invalid time format: {schedule_time}")

            # 生成任务ID
            task_id = f"{symbol}_{interval}_{int(time.time())}"

            # 创建任务名称
            if not task_name:
                task_name = f"Fetch {symbol} ({interval})"

            # 创建定时任务
            task = ScheduledTask(
                task_id=task_id,
                name=task_name,
                func=self._fetch_symbol_data,
                symbol=symbol,
                interval=interval,
                schedule_time=schedule_time
            )

            # 添加到调度器
            with self.lock:
                self.tasks[task_id] = task

                # 根据时间安排任务
                if schedule_time:
                    schedule.every().day.at(schedule_time).do(
                        self._execute_task, task_id
                    ).tag(task_id)
                else:
                    # 默认每天9:30执行
                    schedule.every().day.at("09:30").do(
                        self._execute_task, task_id
                    ).tag(task_id)

                # 更新下次运行时间
                self._update_next_run_time(task_id)

            self.logger.info(f"Added scheduled task: {task_name} for {symbol}")
            return task_id

        except Exception as e:
            self.logger.error(f"Failed to add task for {symbol}: {e}")
            raise

    def remove_task(self, task_id: str) -> bool:
        """移除定时任务"""
        try:
            with self.lock:
                if task_id not in self.tasks:
                    return False

                # 从调度器中移除
                schedule.clear(task_id)

                # 从任务列表中移除
                del self.tasks[task_id]

            self.logger.info(f"Removed task: {task_id}")
            return True

        except Exception as e:
            self.logger.error(f"Failed to remove task {task_id}: {e}")
            return False

    def _execute_task(self, task_id: str):
        """执行定时任务"""
        try:
            with self.lock:
                if task_id not in self.tasks:
                    return

                task = self.tasks[task_id]
                task.update_status(TaskStatus.RUNNING)

            self.logger.info(f"Executing task: {task.name}")

            # 执行任务
            success = task.func(task.symbol, task.interval)

            # 更新任务状态
            with self.lock:
                if success:
                    task.update_status(TaskStatus.COMPLETED)
                else:
                    task.update_status(TaskStatus.FAILED, "Task execution failed")

                # 更新下次运行时间
                self._update_next_run_time(task_id)

            self.logger.info(f"Task {task.name} completed with status: {task.status.value}")

        except Exception as e:
            with self.lock:
                if task_id in self.tasks:
                    self.tasks[task_id].update_status(TaskStatus.FAILED, str(e))

            self.logger.error(f"Error executing task {task_id}: {e}")

    def _fetch_symbol_data(self, symbol: str, interval: str) -> bool:
        """获取股票数据的任务函数"""
        try:
            self.logger.info(f"Fetching data for {symbol} ({interval})")

            # 获取最后更新日期
            last_date = self.data_storage.get_last_date(symbol, interval)

            if last_date:
                # 增量更新
                new_data = self.data_fetcher.fetch_incremental_update(
                    symbol, last_date, interval
                )
                if not new_data.empty:
                    self.data_storage.merge_data(symbol, new_data, interval)
                    self.logger.info(f"Updated {symbol} with {len(new_data)} new records")
                else:
                    self.logger.info(f"No new data for {symbol}")
            else:
                # 获取完整历史数据
                full_data = self.data_fetcher.fetch_full_history(symbol, interval)
                if not full_data.empty:
                    self.data_storage.save_data(symbol, full_data, interval)
                    self.logger.info(f"Fetched complete history for {symbol}: {len(full_data)} records")
                else:
                    self.logger.error(f"Failed to fetch data for {symbol}")
                    return False

            return True

        except Exception as e:
            self.logger.error(f"Failed to fetch data for {symbol}: {e}")
            return False

    def _update_next_run_time(self, task_id: str):
        """更新任务下次运行时间"""
        try:
            task = self.tasks.get(task_id)
            if not task:
                return

            # 查找下次运行时间
            for job in schedule.jobs:
                if task_id in job.tags:
                    task.next_run = job.next_run
                    break

        except Exception as e:
            self.logger.error(f"Failed to update next run time for {task_id}: {e}")

    def get_task_status(self, task_id: str) -> Optional[Dict[str, Any]]:
        """获取任务状态"""
        with self.lock:
            task = self.tasks.get(task_id)
            if task:
                return task.to_dict()
            return None

    def get_all_tasks(self) -> List[Dict[str, Any]]:
        """获取所有任务状态"""
        with self.lock:
            return [task.to_dict() for task in self.tasks.values()]

    def is_task_running(self, task_id: str) -> bool:
        """检查任务是否正在运行"""
        with self.lock:
            task = self.tasks.get(task_id)
            return task and task.status == TaskStatus.RUNNING

    def get_pending_tasks(self) -> List[str]:
        """获取待执行的任务"""
        with self.lock:
            return [
                task_id for task_id, task in self.tasks.items()
                if task.status == TaskStatus.PENDING
            ]

    def get_failed_tasks(self) -> List[str]:
        """获取失败的任务"""
        with self.lock:
            return [
                task_id for task_id, task in self.tasks.items()
                if task.status == TaskStatus.FAILED
            ]

    def retry_failed_tasks(self):
        """重试失败的任务"""
        failed_tasks = self.get_failed_tasks()
        for task_id in failed_tasks:
            with self.lock:
                if task_id in self.tasks:
                    self.tasks[task_id].update_status(TaskStatus.PENDING)
                    self.tasks[task_id].error_message = None

            self.logger.info(f"Reset task {task_id} to pending status")

    def load_tasks_from_config(self):
        """从配置文件加载任务"""
        try:
            schedule_config = self.settings.get('schedule', {})
            if not schedule_config.get('enabled', False):
                return

            # 加载预设的股票代码
            stock_config = self.settings.get('stock_symbols', {})
            symbols = stock_config.get('favorites', [])

            default_time = schedule_config.get('default_time', '09:30')
            default_interval = self.settings.get('data_fetch', {}).get('default_interval', '1d')

            for symbol in symbols:
                self.add_task(symbol, default_interval, default_time)

            self.logger.info(f"Loaded {len(symbols)} tasks from config")

        except Exception as e:
            self.logger.error(f"Failed to load tasks from config: {e}")

    def save_tasks_to_config(self):
        """保存任务到配置文件"""
        try:
            # 这里可以实现保存任务到配置文件的逻辑
            # 由于配置文件可能包含其他设置，需要谨慎处理
            pass

        except Exception as e:
            self.logger.error(f"Failed to save tasks to config: {e}")

    def cleanup_completed_tasks(self, days: int = 7):
        """清理已完成的任务（保留指定天数）"""
        try:
            cutoff_date = datetime.now() - timedelta(days=days)
            tasks_to_remove = []

            with self.lock:
                for task_id, task in self.tasks.items():
                    if (task.status == TaskStatus.COMPLETED and
                        task.last_run and task.last_run < cutoff_date):
                        tasks_to_remove.append(task_id)

                for task_id in tasks_to_remove:
                    self.remove_task(task_id)

            if tasks_to_remove:
                self.logger.info(f"Cleaned up {len(tasks_to_remove)} completed tasks")

        except Exception as e:
            self.logger.error(f"Failed to cleanup completed tasks: {e}")